#ifndef _REDUCT_ACTION_RULES_H
#define _REDUCT_ACTION_RULES_H

#include "ComboReduct/reduct/reduct.h"
#include <boost/logic/tribool.hpp>

namespace reduct {

  //for ome intriging reason the operator tribool.safe_bool() is not usable
  //because considered private by gcc?
  //so I code one here
  bool safe_bool(boost::tribool t);

  //takes a combo subtree of output type action_result starting at 'it'
  //and compute whether that combo subtree
  //1) always succeeds (in that case it returns true),
  //2) always fails (in that case it returns false),
  //3) sometimes succeeds or fails (in this case it returns unknown)
  boost::tribool get_action_result(const vtree& tr, vtree::iterator it);

  //replace all cond within tr (for 'it') occuring at the initial instant
  void substitute_condition_init_instant(vtree& tr, vtree::iterator it,
					 vtree::iterator cond, vertex sub);
			       
  
  //--------------------------------------------------------------------------
  //General action reduction rules
  //--------------------------------------------------------------------------

  //action_boolean_if(true A B) -> A
  //action_boolean_if(false A B) -> B
  //action_boolean_if(C A A) -> A
  struct reduce_action_if : public crule<reduce_action_if> {
    void operator()(vtree& tr, vtree::iterator it) const;
  };  

  //action_action_if(A B B) -> and_seq(exec_seq(A) B)
  struct reduce_action_action_if : public crule<reduce_action_action_if> {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //T_action_if(action_failure A B) -> B
  //T_action_if(action_success A B) -> A
  //with T in {action, boolean, contin}
  struct reduce_const_cond_action_if:public crule<reduce_const_cond_action_if>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //action_boolean_if(not(A) B C) -> action_boolean_if(A C B)
  struct reduce_not_cond_action_boolean_if:public
    crule<reduce_not_cond_action_boolean_if> {
    void operator()(vtree& tr, vtree::iterator it) const;
  };

  //and_seq(A action_failure B) -> and_seq(A action_failure)
  //and_seq(A action_success B) -> and_seq(A B)
  //or_seq(A action_failure B) -> or_seq(A B)
  //or_seq(A action_success B) -> or_seq(A action_success)
  //exec_seq(A action_failure B) -> exec_seq(A B)
  //exec_seq(A action_success C) -> exec_seq(A B)
  struct reduce_const_action_seq : public crule<reduce_const_action_seq>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //and_seq() -> action_success
  //or_seq() -> action_failure
  //exec_seq() -> action_success
  struct reduce_empty_arg_seq : public crule<reduce_empty_arg_seq>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //action_not(action_not(A)) -> A
  struct reduce_double_action_not : public crule<reduce_double_action_not>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };


  //and_seq(A B action_while(B)) -> and_seq(A action_while(B))
  struct reduce_repeat_out_action_while : public
    crule<reduce_repeat_out_action_while> {
    void operator()(vtree& tr,vtree::iterator it) const;
  };
  
  //action_while(and_seq(A A)) -> action_while(A)
  struct reduce_repeat_in_action_while : public
    crule<reduce_repeat_in_action_while> {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //action_boolean_if(C A1 A2) -> action_boolean_if(C A1[C->true] A2[C->false])
  //wherever A1 and A2 has no side effect, or (to rephrase) when evaluation
  //of C within A1 or A2 occurs at the same instant as C within
  //action_boolean_if condition
  struct reduce_action_boolean_if_sub_cond : public
    crule<reduce_action_boolean_if_sub_cond> {
    void operator()(vtree& tr, vtree::iterator it) const;
  };

  //boolean_while(C A) -> boolean_while(C A[C->true])
  //wherever A has no side effect, or to rephrase,
  //when evaluation of C within A occurs at the same instant as
  //C within boolean_while condition.
  struct reduce_boolean_while_sub_cond : public
    crule<reduce_boolean_while_sub_cond> {
    void operator()(vtree& tr, vtree::iterator it) const;
  };
  
  //--------------------------------------------------------------------------
  //Action reduction rules based on always_succeeds properties
  //--------------------------------------------------------------------------

  //action_action_if(A B C) -> and_seq(A B) iff get_action_result(A)==true
  struct reduce_action_action_if_always_succeeds :
    public crule<reduce_action_action_if_always_succeeds>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };
  
  //action_action_if(A B C) -> exec_seq(A C) iff get_action_result(A)==false
  struct reduce_action_action_if_always_fails :
    public crule<reduce_action_action_if_always_fails>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };
  
  //action_while(A) -> A iff get_action_result(A)==false
  struct reduce_action_while_always_fails :
    public crule<reduce_action_while_always_fails>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };

  //boolean_while(C A) -> action_sucess iff eval(C)==false
  //boolean_while(C A) -> A iff eval(C)==true and get_action_result(A)==false
  struct reduce_boolean_while_depend_condition :
    public crule<reduce_boolean_while_depend_condition>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };

  //and_seq(A1 ... An ... Am) -> and_seq(A1 ... An)
  //iff exists n and for all i<n, get_action_result(Ai) = true or undetermined
  //and get_action_result(An)==false
  struct reduce_sequential_and_always_fails :
    public crule<reduce_sequential_and_always_fails>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };
 
  //or_seq(A1 ... An ... Am) -> or_seq(A1 ... An)
  //iff exists n and for all i<n, get_action_result(Ai) = false or undetermined
  //and get_action_result(An)==true
  struct reduce_sequential_or_always_succeeds :
    public crule<reduce_sequential_or_always_succeeds>
  {
    void operator()(vtree& tr, vtree::iterator it) const;
  };

  //--------------------------------------------------------------------------
  //Action reduction rules depending on properties
  //--------------------------------------------------------------------------
  
  //reduce 2 consecutive actions to 1 action
  struct reduce_idempotent : public crule<reduce_idempotent>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };

  //reduce 2 consecutive opposite actions A1 A2
  //that is A1 is the reversal of A2
  struct reduce_opposite : public crule<reduce_opposite>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };
  

  //reduce 2 consecutive actions to 1 action and add the arguments that
  //are denoted additive by is_additive(action,int i);
  //the argument that are not denoted additive must be equal
  struct reduce_additive : public crule<reduce_additive>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };


  //replace action by action_success if exists 0 in one of its argument
  //neutral
  struct reduce_zero_neutral : public crule<reduce_zero_neutral>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };



  //--------------------------------------------------------------------------
  //Reduction rules for modular arguments
  //--------------------------------------------------------------------------

  //action_with_modular_argument(m) -> action_with_modular_argument(reduced(m)) 
  //for example, dummy_modular_action(6.28,-20)-> dummy_modular_action(0,-10)
  struct reduce_modular_argument : public crule<reduce_modular_argument>
  {
    void operator()(vtree& tr,vtree::iterator it) const;
  };


  //--------------------------------------------------------------------------
  // Preconditions checks
  //--------------------------------------------------------------------------

  //preconditions checks
  //for example, if there is a precondition pair (grab drop), then:
  // and_seq(bark drop)-> and_seq(bark action_success)
  // and_seq(grab bark drop)-> and_seq(grab bark drop)
  // and_seq(grab drop drop)-> and_seq(grab drop action_success)
  // and_seq(bark drop drop)-> and_seq(bark action_success action_success)
  // and_seq(or_seq(grab bark) drop bark)-> and_seq(or_seq(grab bark) drop bark)
  // and_seq(or_seq(bark bark) drop bark)-> and_seq(or_seq(bark bark) action_success bark)
  struct preconditions_check : public crule<preconditions_check>
  {
    void operator() (vtree& tr,vtree::iterator it) const;
  }; 

  //auxilary function for the preconditions check
  bool reduce_free_post_action (builtin_action pre_a, builtin_action post_a, bool free_pre_action_before, vtree& tr,vtree::iterator it);  




}

#endif
